package ce.com.cenewbluesdk.ota.ota_modea;



import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import ce.com.cenewbluesdk.uitl.ByteUtil;
import ce.com.cenewbluesdk.uitl.CRC16;

/**
 * Created by Administrator on 2015/12/25 0025.
 */
public class OTASendEntity {

    public static final int FILE_TYPE_NULL = 0;
    public static final int FILE_TYPE_CUSTOMER = 1;  //  客户
    public static final int FILE_TYPE_HARDWARE = 2;  // 设备号
    public static final int FILE_TYPE_CODE = 3;   //  code
    public static final int FILE_TYPE_PIC = 4;//  图片
    public static final int FILE_TYPE_FONT = 5;// 字库
    public static final int FILE_TYPE_DATA = 6;

    public static final int OTA_NONE = 0;        //未升级
    public static final int OTA_RUNING = 1;        //正在升级过程中
    public static final int OTA_FINISH_SUCCESS = 2;        //升级成功
    public static final int OTA_FINISH_WRONG = 3;        //升级错误
    public static final int OTA_IMG_SIZE_ERROR = 4;        //镜像文件的总长度错误
    public static final int OTA_IMG_CRC16_ERROR = 5;    //镜像文件的CRC16值错误
    public static final int OTA_ITEM_HEAD_LEN_ERROR = 6; //单个条目头的长度值错误，
    public static final int OTA_ITEM_HEAD_LEN_ERROR_ALL = OTA_ITEM_HEAD_LEN_ERROR + 10;
    public static final int OTA_ITEM_MEDIA_ERROR = 17; //单个条目的存储介质错误
    public static final int OTA_ITEM_MEDIA_ERROR_ALL = OTA_ITEM_MEDIA_ERROR + 10;
    public static final int OTA_ITEM_SIZE_ERROR = 28; //单个条目的文件长度错误
    public static final int OTA_ITEM_SIZE_ERROR_ALL = OTA_ITEM_SIZE_ERROR + 10;
    public static final int OTA_ITEM_CRC16_ERROR = 39; //单个条目文件的CRC16错误，
    public static final int OTA_ITEM_CRC16_ERROR_ALL = OTA_ITEM_CRC16_ERROR + 10;

    public static final int DF_SendOTAbytesLen = 900;

    private ArrayList<Otak3Entity> mOtak3Entities = new ArrayList<>();
    private int dateLen;
    private byte[] sendBytes;

    private int otaFileLen;

    private int otaFileCRC;

    private int lastSendBytesLen;

    public int getLastSendBytesLen() {
        return lastSendBytesLen;
    }

    public int getOtaFileLen() {
        return otaFileLen;
    }

    public int getOtaFileCRC() {
        return otaFileCRC;
    }

    /**
     * 这个是用来判断整个OTA文件是否正确
     */
//    private boolean otaSendEntityIsOK = true;
//    private String OTAItemErrorString;
//    public boolean isOtaSendEntityIsOK() {
//        return otaSendEntityIsOK;
//    }

//    public String getOTAItemErrorString() {
//        return OTAItemErrorString;
//    }
    public byte[] getSendIndexDate(int index) {

        if (index >= otaFileLen) {
            return null;
        }

        lastSendBytesLen = index + DF_SendOTAbytesLen <= otaFileLen ? DF_SendOTAbytesLen : otaFileLen - index;
        byte[] bytes = new byte[lastSendBytesLen];
        System.arraycopy(sendBytes, index, bytes, 0, lastSendBytesLen);
        return bytes;
    }

    /**
     * 传进来的是设备的版本号  不是文件的版本号。
     * 传进来的MAP  的建是 文件的类型， code  pic 等等
     * 值是对应的版本号
     * @param devVersionMap
     */
    public void initOTAData(Map<Integer, Integer> devVersionMap) {
        if (devVersionMap.size() != mOtak3Entities.size()) {
            OtaUtil.otaLog("传入进来的版本号Map 与文件解析出来的Item 数不一样，说明需要版本号长度发生了变化，需要全部升级" + devVersionMap.size() + "   ____   " + mOtak3Entities.size());
            generateSendBytes(mOtak3Entities);
            return;
        }
        ArrayList<Otak3Entity> otaItemEntitys = new ArrayList<>();
        for (Otak3Entity otak3Entity : mOtak3Entities) {
            if (otak3Entity.getFile_type() == FILE_TYPE_FONT ||
                    otak3Entity.getFile_type() == FILE_TYPE_HARDWARE) {  //这里需要过滤字库  还要过滤设备号
                continue;
            }

            int fileItemVersion = otak3Entity.getVersion_id();
            int devItemVersion = devVersionMap.get((int) otak3Entity.getFile_type());// 一定要转成int~~
            if (fileItemVersion != devItemVersion) {
                otaItemEntitys.add(otak3Entity);
            }
        }
        generateSendBytes(otaItemEntitys);
    }

    private void generateSendBytes(ArrayList<Otak3Entity> otaItemEntitys) {
        for (Otak3Entity otak3Entity : otaItemEntitys) {
            dateLen = dateLen + otak3Entity.getEntityLen();
        }
        otaFileLen = dateLen + 7;
        sendBytes = new byte[otaFileLen];
        int index = 7;
        for (Otak3Entity otak3Entity : otaItemEntitys) {
            if (OtaUtil.checkCrc16OK(ByteUtil.byte2ToInt(otak3Entity.crc16), otak3Entity.data)) {

                OtaUtil.otaLog("item 的crc   ok， +" + otak3Entity.file_type);
            } else {
                OtaUtil.otaLog("item 的crc错了， +" + otak3Entity.file_type);
            }
            OtaUtil.otaLog("合成文件时ITem的crc=" + ByteUtil.byte2ToInt(otak3Entity.crc16));

            OtaUtil.otaLog(otak3Entity.toString());
            OtaUtil.otaLog(" 111   saddr=" + ByteUtil.byte4ToInt(otak3Entity.start_addr) + "   eaddr=" + ByteUtil.byte4ToInt(otak3Entity.end_addr));

            System.arraycopy(otak3Entity.getSendData(), 0, sendBytes, index, otak3Entity.getEntityLen());
            index = index + otak3Entity.getEntityLen();
        }

        sendBytes[6] = (byte) otaItemEntitys.size();
        System.arraycopy(ByteUtil.intToByte4(otaFileLen), 0, sendBytes, 0, 4);
        OtaUtil.otaLog("sendBytes[6]=" + sendBytes[6]);
        otaFileCRC = CRC16.crc16(sendBytes, 6);
        OtaUtil.otaLog("新生成的文件的Ota crc=" + otaFileCRC + "   otaFileLen=" + otaFileLen + "  index=" + index);
        System.arraycopy(ByteUtil.int2bytes2(otaFileCRC), 0, sendBytes, 4, 2);
    }

    public Map<Integer, Integer> getVersionMap() {
        Map<Integer, Integer> map = new HashMap<>();
        for (Otak3Entity entity : mOtak3Entities) {
            map.put((int) entity.getFile_type(), (int) entity.getVersion_id());
        }
        return map;
    }

    public OTASendEntity(byte[] bytes, int itemCount) throws OtaFileException {
        int index = 0;
        //没有处理的ItemData
        if (mOtak3Entities != null) {
            mOtak3Entities.clear();
        } else {
            mOtak3Entities = new ArrayList<>();
        }

        String[] logMsgs = new String[itemCount];
        for (int i = 0; i < itemCount; i++) {
            if (index + Otak3Entity.itemHeadLen > bytes.length) {
                throw new OtaFileException("OtaItem 文件解析长度出了问题");
            }
            byte headLen = bytes[index];
            byte file_type = bytes[index + 1];
            byte version_id = bytes[index + 2];
            byte media_type = bytes[index + 3];
            byte[] saddr = new byte[]{bytes[index + 4], bytes[index + 5], bytes[index + 6], bytes[index + 7]};
            byte[] eaddr = new byte[]{bytes[index + 8], bytes[index + 9], bytes[index + 10], bytes[index + 11]};

            OtaUtil.otaLog("file_type=" + file_type);

            OtaUtil.otaLog("saddr=" + ByteUtil.byte4ToInt(saddr) + "   eaddr=" + ByteUtil.byte4ToInt(eaddr));
            int len = ByteUtil.byte4ToInt(new byte[]{bytes[index + 12], bytes[index + 13], bytes[index + 14], bytes[index + 15]});
            int crc16 = ByteUtil.byte2ToInt(new byte[]{bytes[index + 16], bytes[index + 17]});

            byte[] data = new byte[len];
            if (index + Otak3Entity.itemHeadLen + len > bytes.length) {
                throw new OtaFileException("长度错误?");
            }
            System.arraycopy(bytes, index + Otak3Entity.itemHeadLen, data, 0, len);
            OtaUtil.otaLog("解析文件时ITem的crc=" + crc16);
            if (!OtaUtil.checkCrc16OK(crc16, data)) {
                logMsgs[i] = "item 的crc16错误  错误的item是第" + i + "个";
                continue;// TODO: 2016/2/2 为什么不break?
            } else {
                logMsgs[i] = "ok";
                OtaUtil.otaLog("item 的crc16  OK  OK的item是第" + i + "个");
            }

            Otak3Entity otak3Entity = new Otak3Entity(headLen, file_type, version_id, media_type, saddr, eaddr, len, crc16, data);
            //  DealOtaFile.otaLog(otak3Entity.toString());
            mOtak3Entities.add(otak3Entity);
            index = index + Otak3Entity.itemHeadLen + len;
        }

        if (mOtak3Entities.size() != itemCount) {
            throw new OtaFileException("item 的数量不对,mOtak3Entities list的size是" + mOtak3Entities.size() + "  itemCount=" + itemCount + ", log:" + Arrays.toString(logMsgs));
        }
    }

    class Otak3Entity {

        private byte headLen;
        private byte file_type;            //文件数据类型，参见OTA_FILE_TYPE。
        private byte version_id;        //条目文件版本ID号，0~255.// TODO: 2016/2/2 不是最大255吗?, 可以用byte存?
        private byte media_type;        //数据存储介质类型，0：内部flash , 1：外部flash
        private byte[] start_addr = new byte[4];            //数据存储范围的开始地址。
        private byte[] end_addr = new byte[4];            //数据存储范围的结束地址。

        private byte[] len = new byte[4];            //数据长度大小。4byte
        private byte[] crc16 = new byte[2];            //数据的CRC16校验值。2byte
        private byte[] data;            //具体的数据内容，xxx = len.

        private int entityLen;   //这一个Item的长度

        public final static int itemHeadLen = 18;

        public Otak3Entity(byte headLen, byte file_type, byte version_id, byte media_type, byte start_addr[], byte end_addr[], int len, int crc16, byte[] data) {
            this.headLen = headLen;
            this.file_type = file_type;
            this.version_id = version_id;
            this.media_type = media_type;

            this.crc16[0] = (byte) ((crc16) & 0xff);
            this.crc16[1] = (byte) ((crc16 >>> 8) & 0xff);

            this.len[0] = (byte) ((len) & 0xff);
            this.len[1] = (byte) ((len >>> 8) & 0xff);
            this.len[2] = (byte) ((len >>> 16) & 0xff);
            this.len[3] = (byte) ((len >>> 24) & 0xff);

            this.start_addr = start_addr;
            this.end_addr = end_addr;

            this.data = data;
            entityLen = len + itemHeadLen;

        }

        public byte[] getSendData() {
            byte[] sendDate = new byte[data.length + itemHeadLen];
            sendDate[0] = headLen;
            sendDate[1] = file_type;
            sendDate[2] = version_id;
            sendDate[3] = media_type;
            System.arraycopy(start_addr, 0, sendDate, 4, start_addr.length);
            System.arraycopy(end_addr, 0, sendDate, 8, end_addr.length);
            System.arraycopy(len, 0, sendDate, 12, len.length);
            System.arraycopy(crc16, 0, sendDate, 16, crc16.length);
            System.arraycopy(data, 0, sendDate, 18, data.length);
            return sendDate;
        }

        public byte[] getCrc16() {
            return crc16;
        }

        public int getEntityLen() {
            return entityLen;
        }

        public byte getVersion_id() {
            return version_id;
        }

        public byte getFile_type() {
            return file_type;
        }

        @Override
        public String toString() {
            return "Otak3Entity{" +
                    "file_type=" + file_type +
                    "\n, version_id=" + version_id +
                    "\n, media_type=" + media_type +
                    "\n, entityLen=" + entityLen +
                    "\n, start_addr=" + Arrays.toString(start_addr) +
                    "\n, end_addr=" + Arrays.toString(end_addr) +
                    "\n, len=" + Arrays.toString(len) +
                    "\n, crc16=" + Arrays.toString(crc16) +
                    //     "\n, data=" + Arrays.toString(data) +
                    '}';
        }
    }

}
